﻿using System;

namespace Validate.Net.Core
{
    /// <summary>
    /// 表示自定义校验特性的基类。
    /// <para>如果要让特性可以自定义内联提示语，则实现构造方法，并把参数 <see langword="internalPrompts"/> 传递给 <see cref="ValidateBaseAttribute(string)"/></para>
    /// <para>提示语优先级: <see cref="InternalPrompts"/> > <see cref="CustomPrompts.Set{T}(string)"/> > <see cref="Prompts"/></para>
    /// </summary>
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
    public abstract class ValidateBaseAttribute : Attribute
    {

        /// <summary>
        /// 内联提示语。优先级最高
        /// </summary>
        internal string InternalPrompts { get; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="internalPrompts">内联提示语。优先级最高
        /// <list type="bullet">
        /// <item>提示语只描述校验失败的原因，而不应该包含其他内容。（ 例如 : 不能是默认值、必须填写 等等类似的语句 )</item>
        /// <item>内联提示语将覆盖所有其他设置</item>
        /// <item>提示语优先级: <see cref="ValidateBaseAttribute.InternalPrompts"/> > <see cref="CustomPrompts.Set{T}(string)"/> > <see cref="ValidateBaseAttribute.Prompts"/></item>
        /// </list>
        /// </param>
        public ValidateBaseAttribute(string internalPrompts)
        {
            if (string.IsNullOrWhiteSpace(internalPrompts))
            {
                InternalPrompts = null; // 为了可以进行 ?? 运算符
            }
            else
            {
                InternalPrompts = internalPrompts;
            }
        }


        /// <summary>
        /// 校验失败的默认提示语。优先级最低
        /// <list type="bullet">
        /// <item>提示语只描述校验失败的原因，而不应该包含其他内容。（ 例如 : 不能是默认值、必须填写 等等类似的语句 )</item>
        /// <item>仅当没有任何配置时才显示默认提示语</item>
        /// <item>提示语优先级: <see cref="ValidateBaseAttribute.InternalPrompts"/> > <see cref="CustomPrompts.Set{T}(string)"/> > <see cref="ValidateBaseAttribute.Prompts"/></item>
        /// </list>
        /// </summary>
        public abstract string Prompts { get; }

        /// <summary>
        /// 当校验特性标注的属性时调用。
        /// <list type="bullet">
        /// <item>考虑对 <paramref name="value"/> 进行 <see langword="null"/> 判断，避免出现 <see cref="NullReferenceException"/></item>
        /// <item>考虑 <paramref name="value"/> 为 <see cref="ValueType"/> 的情况</item>
        /// <item>考虑校验逻辑的完整性</item>
        /// <item></item>
        /// </list>
        /// </summary>
        /// <param name="value">属性值</param>
        /// <returns><see langword="true"/>: 校验完成，<see langword="false"/>: 校验失败</returns>
        public abstract bool OnCheck(object value);
    }
}
